#include <iostream>
#include <string.h>

using namespace std;

class String{
public:
    String()
        :_pstr(new char[5]()+4)
    {
        cout << "String()" << endl;
        *(int *)(_pstr-4)=1;
    }

    String(const char *pstr)
        :_pstr(new char[strlen(pstr)+5]()+4)
    {
        cout << "String(const char *)" << endl;
        strcpy(_pstr,pstr);
        *(int *)(_pstr-4)=1;
    }

    String(const String &rhs)
        :_pstr(rhs._pstr)
    {
        cout << "String(const String &)" << endl;
        ++*(int *)(_pstr-4);
    }

    String &operator=(const String &rhs)
    {
        cout << "String operator=(const String &)" << endl;
        if(this!=&rhs){
            if(--*(int *)(_pstr-4)==0){
                delete[] (_pstr-4);
            }

            _pstr=rhs._pstr;
            ++*(int *)(_pstr-4);
        }
        return *this;
    }

    ~String(){
        cout << "~String" << endl;
        if(--*(int *)(_pstr-4)==0){
            delete[] (_pstr-4);
        }
    }

    const char *c_str() const{
        return _pstr;
    }
    friend ostream &operator<<(ostream &os,String &rhs);

    char &operator[](size_t index){
        if(index<=size()){
            if(*(int *)(_pstr-4)>1){
                char *ptmp=new char[size()+5]()+4;
                strcpy(ptmp,_pstr);

                --*(int *)(_pstr-4);
                _pstr=ptmp;
                *(int *)(_pstr-4)=1;
            }
            return _pstr[index];    
        }
        else{
            static char nullchar='\0';
            return nullchar;
        }

    }

    size_t size() const{
        return strlen(_pstr);
    }

    size_t refcount() const{
        return *(int *)(_pstr-4);
    }

private:
    char *_pstr;
};

ostream &operator<<(ostream &os,String &rhs){
    if(rhs._pstr){
        os<<rhs._pstr;
    }
    return os;
}

void test(){
    String s1("hello");
    String s2=s1;
    cout << "&s1=" << (void *)s1.c_str() << endl;
    cout << "&s2=" << (void *)s2.c_str() << endl;

    cout << "----------------------------" << endl;
    cout << s1[0] << endl;
    s1[0]='H';
    cout << s1 << endl;
    cout << s2[0] << endl;
    cout << s2 << endl;
    cout << s1.refcount() << endl;
    cout << s2.refcount() << endl;
}

int main()
{
    test();
    return 0;
}

